js/src/v8/richards.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
     2 // Redistribution and use in source and binary forms, with or without
     3 // modification, are permitted provided that the following conditions are
     4 // met:
     5 //
     6 //     * Redistributions of source code must retain the above copyright
     7 //       notice, this list of conditions and the following disclaimer.
     8 //     * Redistributions in binary form must reproduce the above
     9 //       copyright notice, this list of conditions and the following
    10 //       disclaimer in the documentation and/or other materials provided
    11 //       with the distribution.
    12 //     * Neither the name of Google Inc. nor the names of its
    13 //       contributors may be used to endorse or promote products derived
    14 //       from this software without specific prior written permission.
    15 //
    16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29 // This is a JavaScript implementation of the Richards
    30 // benchmark from:
    31 //
    32 //    http://www.cl.cam.ac.uk/~mr10/Bench.html
    33 //
    34 // The benchmark was originally implemented in BCPL by
    35 // Martin Richards.
    38 var Richards = new BenchmarkSuite('Richards', 35302, [
    39   new Benchmark("Richards", runRichards)
    40 ]);
    43 /**
    44  * The Richards benchmark simulates the task dispatcher of an
    45  * operating system.
    46  **/
    47 function runRichards() {
    48   var scheduler = new Scheduler();
    49   scheduler.addIdleTask(ID_IDLE, 0, null, COUNT);
    51   var queue = new Packet(null, ID_WORKER, KIND_WORK);
    52   queue = new Packet(queue,  ID_WORKER, KIND_WORK);
    53   scheduler.addWorkerTask(ID_WORKER, 1000, queue);
    55   queue = new Packet(null, ID_DEVICE_A, KIND_DEVICE);
    56   queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
    57   queue = new Packet(queue,  ID_DEVICE_A, KIND_DEVICE);
    58   scheduler.addHandlerTask(ID_HANDLER_A, 2000, queue);
    60   queue = new Packet(null, ID_DEVICE_B, KIND_DEVICE);
    61   queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
    62   queue = new Packet(queue,  ID_DEVICE_B, KIND_DEVICE);
    63   scheduler.addHandlerTask(ID_HANDLER_B, 3000, queue);
    65   scheduler.addDeviceTask(ID_DEVICE_A, 4000, null);
    67   scheduler.addDeviceTask(ID_DEVICE_B, 5000, null);
    69   scheduler.schedule();
    71   if (scheduler.queueCount != EXPECTED_QUEUE_COUNT ||
    72       scheduler.holdCount != EXPECTED_HOLD_COUNT) {
    73     var msg =
    74         "Error during execution: queueCount = " + scheduler.queueCount +
    75         ", holdCount = " + scheduler.holdCount + ".";
    76     throw new Error(msg);
    77   }
    78 }
    80 var COUNT = 1000;
    82 /**
    83  * These two constants specify how many times a packet is queued and
    84  * how many times a task is put on hold in a correct run of richards.
    85  * They don't have any meaning a such but are characteristic of a
    86  * correct run so if the actual queue or hold count is different from
    87  * the expected there must be a bug in the implementation.
    88  **/
    89 var EXPECTED_QUEUE_COUNT = 2322;
    90 var EXPECTED_HOLD_COUNT = 928;
    93 /**
    94  * A scheduler can be used to schedule a set of tasks based on their relative
    95  * priorities.  Scheduling is done by maintaining a list of task control blocks
    96  * which holds tasks and the data queue they are processing.
    97  * @constructor
    98  */
    99 function Scheduler() {
   100   this.queueCount = 0;
   101   this.holdCount = 0;
   102   this.blocks = new Array(NUMBER_OF_IDS);
   103   this.list = null;
   104   this.currentTcb = null;
   105   this.currentId = null;
   106 }
   108 var ID_IDLE       = 0;
   109 var ID_WORKER     = 1;
   110 var ID_HANDLER_A  = 2;
   111 var ID_HANDLER_B  = 3;
   112 var ID_DEVICE_A   = 4;
   113 var ID_DEVICE_B   = 5;
   114 var NUMBER_OF_IDS = 6;
   116 var KIND_DEVICE   = 0;
   117 var KIND_WORK     = 1;
   119 /**
   120  * Add an idle task to this scheduler.
   121  * @param {int} id the identity of the task
   122  * @param {int} priority the task's priority
   123  * @param {Packet} queue the queue of work to be processed by the task
   124  * @param {int} count the number of times to schedule the task
   125  */
   126 Scheduler.prototype.addIdleTask = function (id, priority, queue, count) {
   127   this.addRunningTask(id, priority, queue, new IdleTask(this, 1, count));
   128 };
   130 /**
   131  * Add a work task to this scheduler.
   132  * @param {int} id the identity of the task
   133  * @param {int} priority the task's priority
   134  * @param {Packet} queue the queue of work to be processed by the task
   135  */
   136 Scheduler.prototype.addWorkerTask = function (id, priority, queue) {
   137   this.addTask(id, priority, queue, new WorkerTask(this, ID_HANDLER_A, 0));
   138 };
   140 /**
   141  * Add a handler task to this scheduler.
   142  * @param {int} id the identity of the task
   143  * @param {int} priority the task's priority
   144  * @param {Packet} queue the queue of work to be processed by the task
   145  */
   146 Scheduler.prototype.addHandlerTask = function (id, priority, queue) {
   147   this.addTask(id, priority, queue, new HandlerTask(this));
   148 };
   150 /**
   151  * Add a handler task to this scheduler.
   152  * @param {int} id the identity of the task
   153  * @param {int} priority the task's priority
   154  * @param {Packet} queue the queue of work to be processed by the task
   155  */
   156 Scheduler.prototype.addDeviceTask = function (id, priority, queue) {
   157   this.addTask(id, priority, queue, new DeviceTask(this))
   158 };
   160 /**
   161  * Add the specified task and mark it as running.
   162  * @param {int} id the identity of the task
   163  * @param {int} priority the task's priority
   164  * @param {Packet} queue the queue of work to be processed by the task
   165  * @param {Task} task the task to add
   166  */
   167 Scheduler.prototype.addRunningTask = function (id, priority, queue, task) {
   168   this.addTask(id, priority, queue, task);
   169   this.currentTcb.setRunning();
   170 };
   172 /**
   173  * Add the specified 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  * @param {Task} task the task to add
   178  */
   179 Scheduler.prototype.addTask = function (id, priority, queue, task) {
   180   this.currentTcb = new TaskControlBlock(this.list, id, priority, queue, task);
   181   this.list = this.currentTcb;
   182   this.blocks[id] = this.currentTcb;
   183 };
   185 /**
   186  * Execute the tasks managed by this scheduler.
   187  */
   188 Scheduler.prototype.schedule = function () {
   189   this.currentTcb = this.list;
   190   while (this.currentTcb != null) {
   191     if (this.currentTcb.isHeldOrSuspended()) {
   192       this.currentTcb = this.currentTcb.link;
   193     } else {
   194       this.currentId = this.currentTcb.id;
   195       this.currentTcb = this.currentTcb.run();
   196     }
   197   }
   198 };
   200 /**
   201  * Release a task that is currently blocked and return the next block to run.
   202  * @param {int} id the id of the task to suspend
   203  */
   204 Scheduler.prototype.release = function (id) {
   205   var tcb = this.blocks[id];
   206   if (tcb == null) return tcb;
   207   tcb.markAsNotHeld();
   208   if (tcb.priority > this.currentTcb.priority) {
   209     return tcb;
   210   } else {
   211     return this.currentTcb;
   212   }
   213 };
   215 /**
   216  * Block the currently executing task and return the next task control block
   217  * to run.  The blocked task will not be made runnable until it is explicitly
   218  * released, even if new work is added to it.
   219  */
   220 Scheduler.prototype.holdCurrent = function () {
   221   this.holdCount++;
   222   this.currentTcb.markAsHeld();
   223   return this.currentTcb.link;
   224 };
   226 /**
   227  * Suspend the currently executing task and return the next task control block
   228  * to run.  If new work is added to the suspended task it will be made runnable.
   229  */
   230 Scheduler.prototype.suspendCurrent = function () {
   231   this.currentTcb.markAsSuspended();
   232   return this.currentTcb;
   233 };
   235 /**
   236  * Add the specified packet to the end of the worklist used by the task
   237  * associated with the packet and make the task runnable if it is currently
   238  * suspended.
   239  * @param {Packet} packet the packet to add
   240  */
   241 Scheduler.prototype.queue = function (packet) {
   242   var t = this.blocks[packet.id];
   243   if (t == null) return t;
   244   this.queueCount++;
   245   packet.link = null;
   246   packet.id = this.currentId;
   247   return t.checkPriorityAdd(this.currentTcb, packet);
   248 };
   250 /**
   251  * A task control block manages a task and the queue of work packages associated
   252  * with it.
   253  * @param {TaskControlBlock} link the preceding block in the linked block list
   254  * @param {int} id the id of this block
   255  * @param {int} priority the priority of this block
   256  * @param {Packet} queue the queue of packages to be processed by the task
   257  * @param {Task} task the task
   258  * @constructor
   259  */
   260 function TaskControlBlock(link, id, priority, queue, task) {
   261   this.link = link;
   262   this.id = id;
   263   this.priority = priority;
   264   this.queue = queue;
   265   this.task = task;
   266   if (queue == null) {
   267     this.state = STATE_SUSPENDED;
   268   } else {
   269     this.state = STATE_SUSPENDED_RUNNABLE;
   270   }
   271 }
   273 /**
   274  * The task is running and is currently scheduled.
   275  */
   276 var STATE_RUNNING = 0;
   278 /**
   279  * The task has packets left to process.
   280  */
   281 var STATE_RUNNABLE = 1;
   283 /**
   284  * The task is not currently running.  The task is not blocked as such and may
   285 * be started by the scheduler.
   286  */
   287 var STATE_SUSPENDED = 2;
   289 /**
   290  * The task is blocked and cannot be run until it is explicitly released.
   291  */
   292 var STATE_HELD = 4;
   294 var STATE_SUSPENDED_RUNNABLE = STATE_SUSPENDED | STATE_RUNNABLE;
   295 var STATE_NOT_HELD = ~STATE_HELD;
   297 TaskControlBlock.prototype.setRunning = function () {
   298   this.state = STATE_RUNNING;
   299 };
   301 TaskControlBlock.prototype.markAsNotHeld = function () {
   302   this.state = this.state & STATE_NOT_HELD;
   303 };
   305 TaskControlBlock.prototype.markAsHeld = function () {
   306   this.state = this.state | STATE_HELD;
   307 };
   309 TaskControlBlock.prototype.isHeldOrSuspended = function () {
   310   return (this.state & STATE_HELD) != 0 || (this.state == STATE_SUSPENDED);
   311 };
   313 TaskControlBlock.prototype.markAsSuspended = function () {
   314   this.state = this.state | STATE_SUSPENDED;
   315 };
   317 TaskControlBlock.prototype.markAsRunnable = function () {
   318   this.state = this.state | STATE_RUNNABLE;
   319 };
   321 /**
   322  * Runs this task, if it is ready to be run, and returns the next task to run.
   323  */
   324 TaskControlBlock.prototype.run = function () {
   325   var packet;
   326   if (this.state == STATE_SUSPENDED_RUNNABLE) {
   327     packet = this.queue;
   328     this.queue = packet.link;
   329     if (this.queue == null) {
   330       this.state = STATE_RUNNING;
   331     } else {
   332       this.state = STATE_RUNNABLE;
   333     }
   334   } else {
   335     packet = null;
   336   }
   337   return this.task.run(packet);
   338 };
   340 /**
   341  * Adds a packet to the worklist of this block's task, marks this as runnable if
   342  * necessary, and returns the next runnable object to run (the one
   343  * with the highest priority).
   344  */
   345 TaskControlBlock.prototype.checkPriorityAdd = function (task, packet) {
   346   if (this.queue == null) {
   347     this.queue = packet;
   348     this.markAsRunnable();
   349     if (this.priority > task.priority) return this;
   350   } else {
   351     this.queue = packet.addTo(this.queue);
   352   }
   353   return task;
   354 };
   356 TaskControlBlock.prototype.toString = function () {
   357   return "tcb { " + this.task + "@" + this.state + " }";
   358 };
   360 /**
   361  * An idle task doesn't do any work itself but cycles control between the two
   362  * device tasks.
   363  * @param {Scheduler} scheduler the scheduler that manages this task
   364  * @param {int} v1 a seed value that controls how the device tasks are scheduled
   365  * @param {int} count the number of times this task should be scheduled
   366  * @constructor
   367  */
   368 function IdleTask(scheduler, v1, count) {
   369   this.scheduler = scheduler;
   370   this.v1 = v1;
   371   this.count = count;
   372 }
   374 IdleTask.prototype.run = function (packet) {
   375   this.count--;
   376   if (this.count == 0) return this.scheduler.holdCurrent();
   377   if ((this.v1 & 1) == 0) {
   378     this.v1 = this.v1 >> 1;
   379     return this.scheduler.release(ID_DEVICE_A);
   380   } else {
   381     this.v1 = (this.v1 >> 1) ^ 0xD008;
   382     return this.scheduler.release(ID_DEVICE_B);
   383   }
   384 };
   386 IdleTask.prototype.toString = function () {
   387   return "IdleTask"
   388 };
   390 /**
   391  * A task that suspends itself after each time it has been run to simulate
   392  * waiting for data from an external device.
   393  * @param {Scheduler} scheduler the scheduler that manages this task
   394  * @constructor
   395  */
   396 function DeviceTask(scheduler) {
   397   this.scheduler = scheduler;
   398   this.v1 = null;
   399 }
   401 DeviceTask.prototype.run = function (packet) {
   402   if (packet == null) {
   403     if (this.v1 == null) return this.scheduler.suspendCurrent();
   404     var v = this.v1;
   405     this.v1 = null;
   406     return this.scheduler.queue(v);
   407   } else {
   408     this.v1 = packet;
   409     return this.scheduler.holdCurrent();
   410   }
   411 };
   413 DeviceTask.prototype.toString = function () {
   414   return "DeviceTask";
   415 };
   417 /**
   418  * A task that manipulates work packets.
   419  * @param {Scheduler} scheduler the scheduler that manages this task
   420  * @param {int} v1 a seed used to specify how work packets are manipulated
   421  * @param {int} v2 another seed used to specify how work packets are manipulated
   422  * @constructor
   423  */
   424 function WorkerTask(scheduler, v1, v2) {
   425   this.scheduler = scheduler;
   426   this.v1 = v1;
   427   this.v2 = v2;
   428 }
   430 WorkerTask.prototype.run = function (packet) {
   431   if (packet == null) {
   432     return this.scheduler.suspendCurrent();
   433   } else {
   434     if (this.v1 == ID_HANDLER_A) {
   435       this.v1 = ID_HANDLER_B;
   436     } else {
   437       this.v1 = ID_HANDLER_A;
   438     }
   439     packet.id = this.v1;
   440     packet.a1 = 0;
   441     for (var i = 0; i < DATA_SIZE; i++) {
   442       this.v2++;
   443       if (this.v2 > 26) this.v2 = 1;
   444       packet.a2[i] = this.v2;
   445     }
   446     return this.scheduler.queue(packet);
   447   }
   448 };
   450 WorkerTask.prototype.toString = function () {
   451   return "WorkerTask";
   452 };
   454 /**
   455  * A task that manipulates work packets and then suspends itself.
   456  * @param {Scheduler} scheduler the scheduler that manages this task
   457  * @constructor
   458  */
   459 function HandlerTask(scheduler) {
   460   this.scheduler = scheduler;
   461   this.v1 = null;
   462   this.v2 = null;
   463 }
   465 HandlerTask.prototype.run = function (packet) {
   466   if (packet != null) {
   467     if (packet.kind == KIND_WORK) {
   468       this.v1 = packet.addTo(this.v1);
   469     } else {
   470       this.v2 = packet.addTo(this.v2);
   471     }
   472   }
   473   if (this.v1 != null) {
   474     var count = this.v1.a1;
   475     var v;
   476     if (count < DATA_SIZE) {
   477       if (this.v2 != null) {
   478         v = this.v2;
   479         this.v2 = this.v2.link;
   480         v.a1 = this.v1.a2[count];
   481         this.v1.a1 = count + 1;
   482         return this.scheduler.queue(v);
   483       }
   484     } else {
   485       v = this.v1;
   486       this.v1 = this.v1.link;
   487       return this.scheduler.queue(v);
   488     }
   489   }
   490   return this.scheduler.suspendCurrent();
   491 };
   493 HandlerTask.prototype.toString = function () {
   494   return "HandlerTask";
   495 };
   497 /* --- *
   498  * P a c k e t
   499  * --- */
   501 var DATA_SIZE = 4;
   503 /**
   504  * A simple package of data that is manipulated by the tasks.  The exact layout
   505  * of the payload data carried by a packet is not importaint, and neither is the
   506  * nature of the work performed on packets by the tasks.
   507  *
   508  * Besides carrying data, packets form linked lists and are hence used both as
   509  * data and worklists.
   510  * @param {Packet} link the tail of the linked list of packets
   511  * @param {int} id an ID for this packet
   512  * @param {int} kind the type of this packet
   513  * @constructor
   514  */
   515 function Packet(link, id, kind) {
   516   this.link = link;
   517   this.id = id;
   518   this.kind = kind;
   519   this.a1 = 0;
   520   this.a2 = new Array(DATA_SIZE);
   521 }
   523 /**
   524  * Add this packet to the end of a worklist, and return the worklist.
   525  * @param {Packet} queue the worklist to add this packet to
   526  */
   527 Packet.prototype.addTo = function (queue) {
   528   this.link = null;
   529   if (queue == null) return this;
   530   var peek, next = queue;
   531   while ((peek = next.link) != null)
   532     next = peek;
   533   next.link = this;
   534   return queue;
   535 };
   537 Packet.prototype.toString = function () {
   538   return "Packet";
   539 };

mercurial