[JSC] Clean up Object.entries implementation
[WebKit-https.git] / JSTests / microbenchmarks / getter-richards-try-catch.js
1 //@ defaultQuickRun
2
3 // Copyright 2006-2008 the V8 project authors. All rights reserved.
4 // Copyright 2014 Apple Inc.
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 //       notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 //       copyright notice, this list of conditions and the following
13 //       disclaimer in the documentation and/or other materials provided
14 //       with the distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 //       contributors may be used to endorse or promote products derived
17 //       from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31
32 // This is a JavaScript implementation of the Richards
33 // benchmark from:
34 //
35 //    http://www.cl.cam.ac.uk/~mr10/Bench.html
36 //
37 // The benchmark was originally implemented in BCPL by
38 // Martin Richards. It was then ported to JavaScript by the
39 // V8 project authors, and then subsequently it was modified
40 // to use getters and setters by WebKit authors.
41
42 let __exceptionCounter = 0;
43 function randomException() {
44     __exceptionCounter++;
45     if (__exceptionCounter % 2500 === 0)
46         throw new Error("blah");
47 }
48 noInline(randomException);
49
50 /**
51  * The Richards benchmark simulates the task dispatcher of an
52  * operating system.
53  **/
54 function runRichards() {
55     var scheduler = new Scheduler();
56     scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
57
58     var queue = new Packet(null, ID_WORKER, KIND_WORK);
59     queue = new Packet(queue,  ID_WORKER, KIND_WORK);
60     scheduler.addWorkerTask(ID_WORKER, 1000, queue);
61
62     queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE);
63     queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
64     queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
65     scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
66
67     queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE);
68     queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
69     queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
70     scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
71
72     scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
73
74     scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
75
76     scheduler.schedule();
77     let queueCount;
78     try {
79         queueCount = scheduler.queueCount;
80     } catch(e) {
81         queueCount = scheduler.queueCount;
82     }
83     let holdCount;
84     try {
85         holdCount = scheduler.holdCount;
86     } catch(e) { 
87         holdCount = scheduler.holdCount;
88     }
89
90     if (queueCount != EXPECTED_QUEUE_COUNT ||
91         holdCount != EXPECTED_HOLD_COUNT) {
92         var msg =
93             "Error during execution: queueCount = " + queueCount +
94             ", holdCount = " + holdCount + ".";
95         throw new Error(msg);
96     }
97 }
98
99 var COUNT = 1000;
100
101 /**
102  * These two constants specify how many times a packet is queued and
103  * how many times a task is put on hold in a correct run of richards.
104  * They don't have any meaning a such but are characteristic of a
105  * correct run so if the actual queue or hold count is different from
106  * the expected there must be a bug in the implementation.
107  **/
108 var EXPECTED_QUEUE_COUNT = 2322;
109 var EXPECTED_HOLD_COUNT = 928;
110
111
112 /**
113  * A scheduler can be used to schedule a set of tasks based on their relative
114  * priorities.  Scheduling is done by maintaining a list of task control blocks
115  * which holds tasks and the data queue they are processing.
116  * @constructor
117  */
118 function Scheduler() {
119     this._queueCount = 0;
120     this._holdCount = 0;
121     this._blocks = new Array(NUMBER_OF_IDS);
122     this._list = null;
123     this._currentTcb = null;
124     this._currentId = null;
125 }
126
127 var ID_IDLE       = 0;
128 var ID_WORKER     = 1;
129 var ID_HANDLER_A  = 2;
130 var ID_HANDLER_B  = 3;
131 var ID_DEVICE_A   = 4;
132 var ID_DEVICE_B   = 5;
133 var NUMBER_OF_IDS = 6;
134
135 var KIND_DEVICE   = 0;
136 var KIND_WORK     = 1;
137
138 Scheduler.prototype.__defineGetter__("queueCount", function() { randomException(); return this._queueCount; });
139 Scheduler.prototype.__defineSetter__("queueCount", function(value) { this._queueCount = value; });
140 Scheduler.prototype.__defineGetter__("holdCount", function() { randomException(); return this._holdCount; });
141 Scheduler.prototype.__defineSetter__("holdCount", function(value) { this._holdCount = value; });
142 Scheduler.prototype.__defineGetter__("blocks", function() { randomException(); return this._blocks; });
143 Scheduler.prototype.__defineSetter__("blocks", function(value) { this._blocks = value; });
144 Scheduler.prototype.__defineGetter__("list", function() { randomException(); return this._list; });
145 Scheduler.prototype.__defineSetter__("list", function(value) { this._list = value; });
146 Scheduler.prototype.__defineGetter__("currentTcb", function() { randomException(); return this._currentTcb; });
147 Scheduler.prototype.__defineSetter__("currentTcb", function(value) { this._currentTcb = value; });
148 Scheduler.prototype.__defineGetter__("currentId", function() { randomException(); return this._currentId; });
149 Scheduler.prototype.__defineSetter__("currentId", function(value) { this._currentId = value; });
150
151 /**
152  * Add an idle task to this scheduler.
153  * @param {int} id the identity of the task
154  * @param {int} priority the task's priority
155  * @param {Packet} queue the queue of work to be processed by the task
156  * @param {int} count the number of times to schedule the task
157  */
158 Scheduler.prototype.addIdleTask = function (id, priority, queue, count) {
159     this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count));
160 };
161
162 /**
163  * Add a work task to this scheduler.
164  * @param {int} id the identity of the task
165  * @param {int} priority the task's priority
166  * @param {Packet} queue the queue of work to be processed by the task
167  */
168 Scheduler.prototype.addWorkerTask = function (id, priority, queue) {
169     this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0));
170 };
171
172 /**
173  * Add a handler task to this scheduler.
174  * @param {int} id the identity of the task
175  * @param {int} priority the task's priority
176  * @param {Packet} queue the queue of work to be processed by the task
177  */
178 Scheduler.prototype.addHandlerTask = function (id, priority, queue) {
179     this.addTask(id, priority, queue, new HandlerTask(this));
180 };
181
182 /**
183  * Add a handler task to this scheduler.
184  * @param {int} id the identity of the task
185  * @param {int} priority the task's priority
186  * @param {Packet} queue the queue of work to be processed by the task
187  */
188 Scheduler.prototype.addDeviceTask = function (id, priority, queue) {
189     this.addTask(id, priority, queue, new DeviceTask(this))
190 };
191
192 /**
193  * Add the specified task and mark it as running.
194  * @param {int} id the identity of the task
195  * @param {int} priority the task's priority
196  * @param {Packet} queue the queue of work to be processed by the task
197  * @param {Task} task the task to add
198  */
199 Scheduler.prototype.addRunningTask = function (id, priority, queue, task) {
200     this.addTask(id, priority, queue, task);
201     let currentTcb;
202     try {
203         currentTcb = this.currentTcb;
204     } catch(e) {
205         currentTcb = this.currentTcb;
206     }
207     currentTcb.setRunning();
208 };
209
210 /**
211  * Add the specified task to this scheduler.
212  * @param {int} id the identity of the task
213  * @param {int} priority the task's priority
214  * @param {Packet} queue the queue of work to be processed by the task
215  * @param {Task} task the task to add
216  */
217 Scheduler.prototype.addTask = function (id, priority, queue, task) {
218     let list;
219     try {
220         list = this.list;
221     } catch(e) {
222         list = this.list;
223     }
224
225     this.currentTcb = new TaskControlBlock(list, id, priority, queue, task);
226     let currentTcb;
227     try {
228         currentTcb = this.currentTcb;
229     } catch(e) {
230         currentTcb = this.currentTcb;
231     }
232     this.list = currentTcb;
233     let blocks;
234     try {
235         blocks = this.blocks;
236     } catch(e) {
237         blocks = this.blocks;
238     }
239
240     try {
241         currentTcb = this.currentTcb;
242     } catch(e) {
243         currentTcb = this.currentTcb;
244     }
245     blocks[id] = currentTcb;
246 };
247
248 /**
249  * Execute the tasks managed by this scheduler.
250  */
251 Scheduler.prototype.schedule = function () {
252     let list;
253     try {
254         list = this.list;
255     } catch(e) {
256         list = this.list;
257     }
258     this.currentTcb = list;
259     while (true) {
260         let currentTcb;
261
262         try {
263             currentTcb = this.currentTcb;
264         } catch(e) {
265             currentTcb = this.currentTcb;
266         }
267
268         if (currentTcb == null)
269             break;
270
271         try {
272             currentTcb = this.currentTcb;
273         } catch(e) {
274             currentTcb = this.currentTcb;
275         }
276
277         if (currentTcb.isHeldOrSuspended()) {
278             let link;
279             try {
280                 link = currentTcb.link;
281             } catch(e) {
282                 link = currentTcb.link;
283             }
284             this.currentTcb = link;
285         } else {
286             let id;
287             try {
288                 id = currentTcb.id;
289             } catch(e) {
290                 id = currentTcb.id;
291             }
292             this.currentId = id;
293             this.currentTcb = currentTcb.run();
294         }
295     }
296 };
297
298 /**
299  * Release a task that is currently blocked and return the next block to run.
300  * @param {int} id the id of the task to suspend
301  */
302 Scheduler.prototype.release = function (id) {
303     let blocks;
304     try {
305         blocks = this.blocks;
306     } catch(e) {
307         blocks = this.blocks;
308     }
309     var tcb = blocks[id];
310     if (tcb == null) return tcb;
311     tcb.markAsNotHeld();
312
313     let currentTcb;
314     try {
315         currentTcb = this.currentTcb;
316     } catch(e) {
317         currentTcb = this.currentTcb;
318     }
319
320     if (tcb.priority > currentTcb.priority) {
321         return tcb;
322     } else {
323         let currentTcb;
324         try {
325             currentTcb = this.currentTcb;
326         } catch(e) {
327             currentTcb = this.currentTcb;
328         }
329         return currentTcb;
330     }
331 };
332
333 /**
334  * Block the currently executing task and return the next task control block
335  * to run.  The blocked task will not be made runnable until it is explicitly
336  * released, even if new work is added to it.
337  */
338 Scheduler.prototype.holdCurrent = function () {
339     let holdCount;
340     try {
341         holdCount = this.holdCount;
342     } catch(e) {
343         holdCount = this.holdCount;
344     }
345     holdCount++;
346     this.holdCount = holdCount;
347     let currentTcb;
348     try {
349         currentTcb = this.currentTcb;
350     } catch(e) {
351         currentTcb = this.currentTcb;
352     }
353     currentTcb.markAsHeld();
354
355     try {
356         currentTcb = this.currentTcb;
357     } catch(e) {
358         currentTcb = this.currentTcb;
359     }
360
361     let link;
362     try {
363         link = currentTcb.link;
364     } catch(e) {
365         link = currentTcb.link;
366     }
367     return link;
368 };
369
370 /**
371  * Suspend the currently executing task and return the next task control block
372  * to run.  If new work is added to the suspended task it will be made runnable.
373  */
374 Scheduler.prototype.suspendCurrent = function () {
375     let currentTcb;
376     try {
377         currentTcb = this.currentTcb;
378     } catch(e) {
379         currentTcb = this.currentTcb;
380     }
381     currentTcb.markAsSuspended();
382     try {
383         currentTcb = this.currentTcb;
384     } catch(e) {
385         currentTcb = this.currentTcb;
386     }
387     return currentTcb;
388 };
389
390 /**
391  * Add the specified packet to the end of the worklist used by the task
392  * associated with the packet and make the task runnable if it is currently
393  * suspended.
394  * @param {Packet} packet the packet to add
395  */
396 Scheduler.prototype.queue = function (packet) {
397     let blocks;
398     try {
399         blocks = this.blocks;
400     } catch(e) {
401         blocks = this.blocks;
402     }
403     let id;
404     try {
405         id = packet.id;
406     } catch(e) {
407         id = packet.id;
408     }
409     var t = blocks[id];
410     if (t == null) return t;
411     let queueCount;
412     try {
413         queueCount = this.queueCount;
414     } catch(e) {
415         queueCount = this.queueCount;
416     }
417     queueCount++;
418     this.queueCount = queueCount;
419     try {
420         packet.link = null;
421     } catch(e) { }
422     let currentId;
423     try {
424         currentId = this.currentId;
425     } catch(e) {
426         currentId = this.currentId;
427     }
428     try {
429         packet.id = currentId;
430     } catch(e) { }
431     let currentTcb;
432     try {
433         currentTcb = this.currentTcb;
434     } catch(e) {
435         currentTcb = this.currentTcb;
436     }
437     return t.checkPriorityAdd(currentTcb, packet);
438 };
439
440 /**
441  * A task control block manages a task and the queue of work packages associated
442  * with it.
443  * @param {TaskControlBlock} link the preceding block in the linked block list
444  * @param {int} id the id of this block
445  * @param {int} priority the priority of this block
446  * @param {Packet} queue the queue of packages to be processed by the task
447  * @param {Task} task the task
448  * @constructor
449  */
450 function TaskControlBlock(link, id, priority, queue, task) {
451     this._link = link;
452     this._id = id;
453     this._priority = priority;
454     this._queue = queue;
455     this._task = task;
456     if (queue == null) {
457         try {
458             this.state = STATE_SUSPENDED;
459         } catch(e) { }
460     } else {
461         try {
462             this.state = STATE_SUSPENDED_RUNNABLE;
463         } catch(e) { }
464     }
465 }
466
467 /**
468  * The task is running and is currently scheduled.
469  */
470 var STATE_RUNNING = 0;
471
472 /**
473  * The task has packets left to process.
474  */
475 var STATE_RUNNABLE = 1;
476
477 /**
478  * The task is not currently running.  The task is not blocked as such and may
479  * be started by the scheduler.
480  */
481 var STATE_SUSPENDED = 2;
482
483 /**
484  * The task is blocked and cannot be run until it is explicitly released.
485  */
486 var STATE_HELD = 4;
487
488 var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
489 var STATE_NOT_HELD = ~STATE_HELD;
490
491 TaskControlBlock.prototype.__defineGetter__("link", function() { randomException(); return this._link; });
492 TaskControlBlock.prototype.__defineGetter__("id", function() { randomException(); return this._id; });
493 TaskControlBlock.prototype.__defineGetter__("priority", function() { return this._priority; });
494 TaskControlBlock.prototype.__defineGetter__("queue", function() { randomException(); return this._queue; });
495 TaskControlBlock.prototype.__defineSetter__("queue", function(value) { this._queue = value; });
496 TaskControlBlock.prototype.__defineGetter__("task", function() { return this._task; });
497 TaskControlBlock.prototype.__defineGetter__("state", function() { randomException(); return this._state; });
498 TaskControlBlock.prototype.__defineSetter__("state", function(value) { this._state = value; randomException(); });
499
500 TaskControlBlock.prototype.setRunning = function () {
501     try {
502         this.state = STATE_RUNNING;
503     } catch(e) { }
504 };
505
506 TaskControlBlock.prototype.markAsNotHeld = function () {
507     let state;
508     try {
509         state = this.state;
510     } catch(e) {
511         state = this.state;
512     }
513     try {
514         this.state = state & STATE_NOT_HELD;
515     } catch(e){}
516 };
517
518 TaskControlBlock.prototype.markAsHeld = function () {
519     let state;
520     try {
521         state = this.state;
522     } catch(e) {
523         state = this.state;
524     }
525     try {
526         this.state = state | STATE_HELD;
527     } catch(e) {}
528 };
529
530 TaskControlBlock.prototype.isHeldOrSuspended = function () {
531     let state;
532     try {
533         state = this.state;
534     } catch(e) {
535         state = this.state;
536     }
537     return (state & STATE_HELD) != 0 || (state == STATE_SUSPENDED);
538 };
539
540 TaskControlBlock.prototype.markAsSuspended = function () {
541     let state;
542     try {
543         state = this.state;
544     } catch(e) {
545         state = this.state;
546     }
547     try {
548         this.state = state | STATE_SUSPENDED;
549     } catch(e) { }
550 };
551
552 TaskControlBlock.prototype.markAsRunnable = function () {
553     let state;
554     try {
555         state = this.state;
556     } catch(e) {
557         state = this.state;
558     }
559     try {
560         this.state = state | STATE_RUNNABLE;
561     } catch(e) { }
562 };
563
564 /**
565  * Runs this task, if it is ready to be run, and returns the next task to run.
566  */
567 TaskControlBlock.prototype.run = function () {
568     var packet;
569     let state;
570     try {
571         state = this.state;
572     } catch(e) {
573         state = this.state;
574     }
575     if (state == STATE_SUSPENDED_RUNNABLE) {
576         let queue;
577         try {
578             queue = this.queue;
579         } catch(e) {
580             queue = this.queue;
581         }
582         packet = queue;
583         let link;
584         try {
585             link = packet.link;
586         } catch(e) {
587             link = packet.link;
588         }
589         this.queue = link;
590         try {
591             queue = this.queue;
592         } catch(e) {
593             queue = this.queue;
594         }
595         if (queue == null) {
596             try {
597                 this.state = STATE_RUNNING;
598             } catch(e) { }
599         } else {
600             try {
601                 this.state = STATE_RUNNABLE;
602             } catch(e) { }
603         }
604     } else {
605         packet = null;
606     }
607     return this.task.run(packet);
608 };
609
610 /**
611  * Adds a packet to the worklist of this block's task, marks this as runnable if
612  * necessary, and returns the next runnable object to run (the one
613  * with the highest priority).
614  */
615 TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) {
616     let queue;
617     try {
618         queue = this.queue;
619     } catch(e) {
620         queue = this.queue;
621     }
622     if (queue == null) {
623         this.queue = packet;
624         this.markAsRunnable();
625         if (this.priority > task.priority) return this;
626     } else {
627         let queue;
628         try {
629             queue = this.queue;
630         } catch(e) {
631             queue = this.queue;
632         }
633         this.queue = packet.addTo(queue);
634     }
635     return task;
636 };
637
638 TaskControlBlock.prototype.toString = function () {
639     let state;
640     try {
641         state = this.state;
642     } catch(e) {
643         state = this.state;
644     }
645     return "tcb { " + this.task + "@" + state + " }";
646 };
647
648 /**
649  * An idle task doesn't do any work itself but cycles control between the two
650  * device tasks.
651  * @param {Scheduler} scheduler the scheduler that manages this task
652  * @param {int} v1 a seed value that controls how the device tasks are scheduled
653  * @param {int} count the number of times this task should be scheduled
654  * @constructor
655  */
656 function IdleTask(scheduler, v1, count) {
657     this._scheduler = scheduler;
658     this._v1 = v1;
659     this._count = count;
660 }
661
662 IdleTask.prototype.__defineGetter__("scheduler", function() { randomException(); return this._scheduler; });
663 IdleTask.prototype.__defineGetter__("v1", function() { randomException(); return this._v1; });
664 IdleTask.prototype.__defineSetter__("v1", function(value) { this._v1 = value; randomException(); });
665 IdleTask.prototype.__defineGetter__("count", function() { randomException(); return this._count; });
666 IdleTask.prototype.__defineSetter__("count", function(value) { this._count = value; randomException(); });
667
668 IdleTask.prototype.run = function (packet) {
669     let count;
670     try {
671         count = this.count;
672     } catch(e) {
673         count = this.count;
674     }
675     try {
676         this.count = count - 1;
677     } catch(e) { }
678     let scheduler;
679     try {
680         scheduler = this.scheduler;
681     } catch(e) {
682         scheduler = this.scheduler;
683     }
684
685     try {
686         count = this.count;
687     } catch(e) {
688         count = this.count;
689     }
690     if (count == 0) return scheduler.holdCurrent();
691     let v1;
692     try {
693         v1 = this.v1;
694     } catch(e) {
695         v1 = this.v1;
696     }
697     if ((v1 & 1) == 0) {
698         let v1;
699         try {
700             v1 = this.v1;
701         } catch(e) {
702             v1 = this.v1;
703         }
704         try {
705             this.v1 = v1 >> 1;
706         } catch(e) { }
707         let scheduler;
708         try {
709             scheduler = this.scheduler;
710         } catch(e) {
711             scheduler = this.scheduler;
712         }
713         return scheduler.release(ID_DEVICE_A);
714     } else {
715         let v1;
716         try {
717             v1 = this.v1;
718         } catch(e) {
719             v1 = this.v1;
720         }
721         try {
722             this.v1 = (v1 >> 1) ^ 0xD008;
723         } catch(e) { }
724         let scheduler;
725         try {
726             scheduler = this.scheduler;
727         } catch(e) {
728             scheduler = this.scheduler;
729         }
730         return scheduler.release(ID_DEVICE_B);
731     }
732 };
733
734 IdleTask.prototype.toString = function () {
735     return "IdleTask"
736 };
737
738 /**
739  * A task that suspends itself after each time it has been run to simulate
740  * waiting for data from an external device.
741  * @param {Scheduler} scheduler the scheduler that manages this task
742  * @constructor
743  */
744 function DeviceTask(scheduler) {
745     this._scheduler = scheduler;
746     this._v1 = null;
747 }
748
749 DeviceTask.prototype.__defineGetter__("scheduler", function() { randomException(); return this._scheduler; });
750 DeviceTask.prototype.__defineGetter__("v1", function() { randomException(); return this._v1; });
751 DeviceTask.prototype.__defineSetter__("v1", function(value) { this._v1 = value; randomException(); });
752
753 DeviceTask.prototype.run = function (packet) {
754     if (packet == null) {
755         let scheduler;
756         try {
757             scheduler = this.scheduler;
758         } catch(e) {
759             scheduler = this.scheduler;
760         }
761         let v1;
762         try {
763             v1 = this.v1;
764         } catch(e) {
765             v1 = this.v1;
766         }
767         if (v1 == null) return scheduler.suspendCurrent();
768         try {
769             v1 = this.v1;
770         } catch(e) {
771             v1 = this.v1;
772         }
773         var v = v1;
774         try {
775             this.v1 = null;
776         } catch(e) { }
777
778         try {
779             scheduler = this.scheduler;
780         } catch(e) {
781             scheduler = this.scheduler;
782         }
783         let queue;
784         try {
785             queue = scheduler.queue;
786         } catch(e) {
787             queue = scheduler.queue;
788         }
789         return queue.bind(scheduler)(v);
790     } else {
791         try {
792             this.v1 = packet;
793         } catch(e) { }
794         let scheduler;
795         try {
796             scheduler = this.scheduler;
797         } catch(e) {
798             scheduler = this.scheduler;
799         }
800         return scheduler.holdCurrent();
801     }
802 };
803
804 DeviceTask.prototype.toString = function () {
805     return "DeviceTask";
806 };
807
808 /**
809  * A task that manipulates work packets.
810  * @param {Scheduler} scheduler the scheduler that manages this task
811  * @param {int} v1 a seed used to specify how work packets are manipulated
812  * @param {int} v2 another seed used to specify how work packets are manipulated
813  * @constructor
814  */
815 function WorkerTask(scheduler, v1, v2) {
816     this._scheduler = scheduler;
817     this._v1 = v1;
818     this._v2 = v2;
819 }
820
821 WorkerTask.prototype.__defineGetter__("scheduler", function() { randomException(); return this._scheduler; });
822 WorkerTask.prototype.__defineGetter__("v1", function() { randomException(); return this._v1; });
823 WorkerTask.prototype.__defineSetter__("v1", function(value) { this._v1 = value; randomException(); });
824 WorkerTask.prototype.__defineGetter__("v2", function() { randomException(); return this._v2; });
825 WorkerTask.prototype.__defineSetter__("v2", function(value) { this._v2 = value; randomException(); });
826
827 WorkerTask.prototype.run = function (packet) {
828     if (packet == null) {
829         let scheduler;
830         try {
831             scheduler = this.scheduler;
832         } catch(e) {
833             scheduler = this.scheduler;
834         }
835         return scheduler.suspendCurrent();
836     } else {
837         let v1;
838         try {
839             v1 = this.v1;
840         } catch(e) {
841             v1 = this.v1;
842         }
843         if (v1 == ID_HANDLER_A) {
844             try {
845                 this.v1 = ID_HANDLER_B;
846             } catch(e){}
847         } else {
848             try {
849                 this.v1 = ID_HANDLER_A;
850             } catch(e) { }
851         }
852         try {
853             v1 = this.v1;
854         } catch(e) {
855             v1 = this.v1;
856         }
857         try {
858             packet.id = v1;
859         } catch(e) { }
860         try {
861             packet.a1 = 0;
862         } catch(e) { }
863         for (var i = 0; i < DATA_SIZE; i++) {
864             let v2;
865             try {
866                 v2 = this.v2;
867             } catch(e) {
868                 v2 = this.v2;
869             }
870             v2++;
871             try {
872                 this.v2 = v2;
873             } catch(e) { }
874             try {
875                 v2 = this.v2;
876             } catch(e) {
877                 v2 = this.v2;
878             }
879             if (v2 > 26) {
880                 try {
881                     this.v2 = 1;
882                 } catch(e) { }
883             } 
884             try {
885                 v2 = this.v2;
886             } catch(e) {
887                 v2 = this.v2;
888             }
889             packet.a2[i] = v2;
890         }
891         let scheduler;
892         try {
893             scheduler = this.scheduler;
894         } catch(e) {
895             scheduler = this.scheduler;
896         }
897         let queue;
898         try {
899             queue = scheduler.queue;
900         } catch(e) {
901             queue = scheduler.queue;
902         }
903         return queue.bind(scheduler)(packet);
904     }
905 };
906
907 WorkerTask.prototype.toString = function () {
908     return "WorkerTask";
909 };
910
911 /**
912  * A task that manipulates work packets and then suspends itself.
913  * @param {Scheduler} scheduler the scheduler that manages this task
914  * @constructor
915  */
916 function HandlerTask(scheduler) {
917     this._scheduler = scheduler;
918     this._v1 = null;
919     this._v2 = null;
920 }
921
922 HandlerTask.prototype.__defineGetter__("scheduler", function() { randomException(); return this._scheduler; });
923 HandlerTask.prototype.__defineGetter__("v1", function() { randomException(); return this._v1; });
924 HandlerTask.prototype.__defineSetter__("v1", function(value) { this._v1 = value; randomException(); });
925 HandlerTask.prototype.__defineGetter__("v2", function() { randomException(); return this._v2; });
926 HandlerTask.prototype.__defineSetter__("v2", function(value) { this._v2 = value; randomException(); });
927
928 HandlerTask.prototype.run = function (packet) {
929     if (packet != null) {
930         let kind;
931         try {
932             kind = packet.kind;
933         } catch(e) {
934             kind = packet.kind;
935         }
936         if (kind == KIND_WORK) {
937             let v1;
938             try {
939                 v1 = this.v1;
940             } catch(e) {
941                 v1 = this.v1;
942             }
943             try {
944                 this.v1 = packet.addTo(v1);
945             } catch(e) { }
946         } else {
947             let v2;
948             try {
949                 v2 = this.v2;
950             } catch(e) {
951                 v2 = this.v2;
952             }
953             try {
954                 this.v2 = packet.addTo(v2);
955             } catch(e) { }
956         }
957     }
958     let v1;
959     try {
960         v1 = this.v1;
961     } catch(e) {
962         v1 = this.v1;
963     }
964     if (v1 != null) {
965         let v1;
966         try {
967             v1 = this.v1;
968         } catch(e) {
969             v1 = this.v1;
970         }
971         var count = v1.a1;
972         var v;
973         if (count < DATA_SIZE) {
974             let v2;
975             try {
976                 v2 = this.v2;
977             } catch(e) {
978                 v2 = this.v2;
979             }
980             if (v2 != null) {
981                 let v2;
982                 try {
983                     v2 = this.v2;
984                 } catch(e) {
985                     v2 = this.v2;
986                 }
987                 v = v2;
988                 let link;
989                 try {
990                     v2 = this.v2;
991                 } catch(e) {
992                     v2 = this.v2;
993                 }
994                 try {
995                     link = v2.link;
996                 } catch(e) {
997                     link = v2.link;
998                 }
999                 try {
1000                     this.v2 = link;
1001                 } catch(e) { }
1002                 let v1;
1003                 try {
1004                     v1 = this.v1;
1005                 } catch(e) {
1006                     v1 = this.v1;
1007                 }
1008                 try {
1009                     v.a1 = v1.a2[count];
1010                 } catch(e) { }
1011                 try {
1012                     v1 = this.v1;
1013                 } catch(e) {
1014                     v1 = this.v1;
1015                 }
1016                 try {
1017                     v1.a1 = count + 1;
1018                 } catch(e) { }
1019                 let scheduler;
1020                 try {
1021                     scheduler = this.scheduler;
1022                 } catch(e) {
1023                     scheduler = this.scheduler;
1024                 }
1025                 let queue;
1026                 try {
1027                     queue = scheduler.queue;
1028                 } catch(e) {
1029                     queue = scheduler.queue;
1030                 }
1031                 return queue.bind(scheduler)(v);
1032             }
1033         } else {
1034             let v1;
1035             try {
1036                 v1 = this.v1;
1037             } catch(e) {
1038                 v1 = this.v1;
1039             }
1040             v = v1;
1041             try {
1042                 v1 = this.v1;
1043             } catch(e) {
1044                 v1 = this.v1;
1045             }
1046             let link;
1047             try {
1048                 link = v1.link;
1049             } catch(e) {
1050                 link = v1.link;
1051             }
1052             try {
1053                 this.v1 = link;
1054             } catch(e) { }
1055             let scheduler;
1056             try {
1057                 scheduler = this.scheduler;
1058             } catch(e) {
1059                 scheduler = this.scheduler;
1060             }
1061             let queue;
1062             try {
1063                 queue = scheduler.queue;
1064             } catch(e) {
1065                 queue = scheduler.queue;
1066             }
1067             return queue.bind(scheduler)(v);
1068         }
1069     }
1070     let scheduler;
1071     try {
1072         scheduler = this.scheduler;
1073     } catch(e) {
1074         scheduler = this.scheduler;
1075     }
1076     return scheduler.suspendCurrent();
1077 };
1078
1079 HandlerTask.prototype.toString = function () {
1080     return "HandlerTask";
1081 };
1082
1083 /* --- *
1084  * P a c k e t
1085  * --- */
1086
1087 var DATA_SIZE = 4;
1088
1089 /**
1090  * A simple package of data that is manipulated by the tasks.  The exact layout
1091  * of the payload data carried by a packet is not importaint, and neither is the
1092  * nature of the work performed on packets by the tasks.
1093  *
1094  * Besides carrying data, packets form linked lists and are hence used both as
1095  * data and worklists.
1096  * @param {Packet} link the tail of the linked list of packets
1097  * @param {int} id an ID for this packet
1098  * @param {int} kind the type of this packet
1099  * @constructor
1100  */
1101 function Packet(link, id, kind) {
1102     this._link = link;
1103     this._id = id;
1104     this._kind = kind;
1105     this._a1 = 0;
1106     this._a2 = new Array(DATA_SIZE);
1107 }
1108
1109 Packet.prototype.__defineGetter__("link", function() { randomException(); return this._link; });
1110 Packet.prototype.__defineSetter__("link", function(value) { this._link = value; randomException(); });
1111 Packet.prototype.__defineGetter__("id", function() { return this._id; });
1112 Packet.prototype.__defineSetter__("id", function(value) { this._id = value; randomException(); });
1113 Packet.prototype.__defineGetter__("kind", function() { randomException(); return this._kind; });
1114 Packet.prototype.__defineGetter__("a1", function() { return this._a1; });
1115 Packet.prototype.__defineSetter__("a1", function(value) { this._a1 = value; randomException(); });
1116 Packet.prototype.__defineGetter__("a2", function() { return this._a2; });
1117
1118 /**
1119  * Add this packet to the end of a worklist, and return the worklist.
1120  * @param {Packet} queue the worklist to add this packet to
1121  */
1122 Packet.prototype.addTo = function (queue) {
1123     try {
1124         this.link = null;
1125     } catch(e) { }
1126     if (queue == null) return this;
1127     var peek, next = queue;
1128     while (true) {
1129         let link;
1130         try {
1131             link = next.link;
1132         } catch(e) {
1133             link = next.link;
1134         }
1135         if (link == null)
1136             break;
1137         peek = link;
1138         next = peek;
1139     }
1140     try {
1141         next.link = this;
1142     } catch(e) { }
1143     return queue;
1144 };
1145
1146 Packet.prototype.toString = function () {
1147     return "Packet";
1148 };
1149
1150 for (var i = 0; i < 30; ++i)
1151     runRichards();