js/src/jit-test/tests/v8-v5/check-splay.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright 2009 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.
    28 // This benchmark is based on a JavaScript log processing module used
    29 // by the V8 profiler to generate execution time profiles for runs of
    30 // JavaScript applications, and it effectively measures how fast the
    31 // JavaScript engine is at allocating nodes and reclaiming the memory
    32 // used for old nodes. Because of the way splay trees work, the engine
    33 // also has to deal with a lot of changes to the large tree object
    34 // graph.
    36 //var Splay = new BenchmarkSuite('Splay', 126125, [
    37 //  new Benchmark("Splay", SplayRun, SplaySetup, SplayTearDown)
    38 //]);
    40 // This is the best random number generator available to mankind ;)
    41 var MyMath = {
    42   seed: 49734321,
    43   random: function() {
    44     // Robert Jenkins' 32 bit integer hash function.
    45     this.seed = ((this.seed + 0x7ed55d16) + (this.seed << 12))  & 0xffffffff;
    46     this.seed = ((this.seed ^ 0xc761c23c) ^ (this.seed >>> 19)) & 0xffffffff;
    47     this.seed = ((this.seed + 0x165667b1) + (this.seed << 5))   & 0xffffffff;
    48     this.seed = ((this.seed + 0xd3a2646c) ^ (this.seed << 9))   & 0xffffffff;
    49     this.seed = ((this.seed + 0xfd7046c5) + (this.seed << 3))   & 0xffffffff;
    50     this.seed = ((this.seed ^ 0xb55a4f09) ^ (this.seed >>> 16)) & 0xffffffff;
    51     return (this.seed & 0xfffffff) / 0x10000000;
    52   },
    53 };
    55 // Configuration.
    56 var kSplayTreeSize = 8000;
    57 var kSplayTreeModifications = 80;
    58 var kSplayTreePayloadDepth = 5;
    60 var splayTree = null;
    63 function GeneratePayloadTree(depth, key) {
    64   if (depth == 0) {
    65     return {
    66       array  : [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
    67       string : 'String for key ' + key + ' in leaf node'
    68     };
    69   } else {
    70     return {
    71       left:  GeneratePayloadTree(depth - 1, key),
    72       right: GeneratePayloadTree(depth - 1, key)
    73     };
    74   }
    75 }
    78 function GenerateKey() {
    79   // The benchmark framework guarantees that Math.random is
    80   // deterministic; see base.js.
    81   // base.js isn't pulled in for jit-tests
    82   return MyMath.random();
    83 }
    86 function InsertNewNode() {
    87   // Insert new node with a unique key.
    88   var key;
    89   do {
    90     key = GenerateKey();
    91   } while (splayTree.find(key) != null);
    92   splayTree.insert(key, GeneratePayloadTree(kSplayTreePayloadDepth, key));
    93   return key;
    94 }
    97 function SplaySetup() {
    98   splayTree = new SplayTree();
    99   for (var i = 0; i < kSplayTreeSize; i++) InsertNewNode();
   100 }
   103 function SplayTearDown() {
   104   // Allow the garbage collector to reclaim the memory
   105   // used by the splay tree no matter how we exit the
   106   // tear down function.
   107   var keys = splayTree.exportKeys();
   108   splayTree = null;
   110   // Verify that the splay tree has the right size.
   111   var length = keys.length;
   112   assertEq(length, kSplayTreeSize);
   114   // Verify that the splay tree has sorted, unique keys.
   115   for (var i = 0; i < length - 1; i++) {
   116     assertEq(keys[i] < keys[i + 1], true);
   117   }
   118 }
   121 function SplayRun() {
   122   // Replace a few nodes in the splay tree.
   123   for (var i = 0; i < kSplayTreeModifications; i++) {
   124     var key = InsertNewNode();
   125     var greatest = splayTree.findGreatestLessThan(key);
   126     if (greatest == null) splayTree.remove(key);
   127     else splayTree.remove(greatest.key);
   128   }
   129 }
   132 /**
   133  * Constructs a Splay tree.  A splay tree is a self-balancing binary
   134  * search tree with the additional property that recently accessed
   135  * elements are quick to access again. It performs basic operations
   136  * such as insertion, look-up and removal in O(log(n)) amortized time.
   137  *
   138  * @constructor
   139  */
   140 function SplayTree() {
   141 };
   144 /**
   145  * Pointer to the root node of the tree.
   146  *
   147  * @type {SplayTree.Node}
   148  * @private
   149  */
   150 SplayTree.prototype.root_ = null;
   153 /**
   154  * @return {boolean} Whether the tree is empty.
   155  */
   156 SplayTree.prototype.isEmpty = function() {
   157   return !this.root_;
   158 };
   161 /**
   162  * Inserts a node into the tree with the specified key and value if
   163  * the tree does not already contain a node with the specified key. If
   164  * the value is inserted, it becomes the root of the tree.
   165  *
   166  * @param {number} key Key to insert into the tree.
   167  * @param {*} value Value to insert into the tree.
   168  */
   169 SplayTree.prototype.insert = function(key, value) {
   170   if (this.isEmpty()) {
   171     this.root_ = new SplayTree.Node(key, value);
   172     return;
   173   }
   174   // Splay on the key to move the last node on the search path for
   175   // the key to the root of the tree.
   176   this.splay_(key);
   177   if (this.root_.key == key) {
   178     return;
   179   }
   180   var node = new SplayTree.Node(key, value);
   181   if (key > this.root_.key) {
   182     node.left = this.root_;
   183     node.right = this.root_.right;
   184     this.root_.right = null;
   185   } else {
   186     node.right = this.root_;
   187     node.left = this.root_.left;
   188     this.root_.left = null;
   189   }
   190   this.root_ = node;
   191 };
   194 /**
   195  * Removes a node with the specified key from the tree if the tree
   196  * contains a node with this key. The removed node is returned. If the
   197  * key is not found, an exception is thrown.
   198  *
   199  * @param {number} key Key to find and remove from the tree.
   200  * @return {SplayTree.Node} The removed node.
   201  */
   202 SplayTree.prototype.remove = function(key) {
   203   if (this.isEmpty()) {
   204     throw Error('Key not found: ' + key);
   205   }
   206   this.splay_(key);
   207   if (this.root_.key != key) {
   208     throw Error('Key not found: ' + key);
   209   }
   210   var removed = this.root_;
   211   if (!this.root_.left) {
   212     this.root_ = this.root_.right;
   213   } else {
   214     var right = this.root_.right;
   215     this.root_ = this.root_.left;
   216     // Splay to make sure that the new root has an empty right child.
   217     this.splay_(key);
   218     // Insert the original right child as the right child of the new
   219     // root.
   220     this.root_.right = right;
   221   }
   222   return removed;
   223 };
   226 /**
   227  * Returns the node having the specified key or null if the tree doesn't contain
   228  * a node with the specified key.
   229  *
   230  * @param {number} key Key to find in the tree.
   231  * @return {SplayTree.Node} Node having the specified key.
   232  */
   233 SplayTree.prototype.find = function(key) {
   234   if (this.isEmpty()) {
   235     return null;
   236   }
   237   this.splay_(key);
   238   return this.root_.key == key ? this.root_ : null;
   239 };
   242 /**
   243  * @return {SplayTree.Node} Node having the maximum key value that
   244  *     is less or equal to the specified key value.
   245  */
   246 SplayTree.prototype.findGreatestLessThan = function(key) {
   247   if (this.isEmpty()) {
   248     return null;
   249   }
   250   // Splay on the key to move the node with the given key or the last
   251   // node on the search path to the top of the tree.
   252   this.splay_(key);
   253   // Now the result is either the root node or the greatest node in
   254   // the left subtree.
   255   if (this.root_.key <= key) {
   256     return this.root_;
   257   } else if (this.root_.left) {
   258     return this.findMax(this.root_.left);
   259   } else {
   260     return null;
   261   }
   262 };
   265 /**
   266  * @return {Array<*>} An array containing all the keys of tree's nodes.
   267  */
   268 SplayTree.prototype.exportKeys = function() {
   269   var result = [];
   270   if (!this.isEmpty()) {
   271     this.root_.traverse_(function(node) { result.push(node.key); });
   272   }
   273   return result;
   274 };
   277 /**
   278  * Perform the splay operation for the given key. Moves the node with
   279  * the given key to the top of the tree.  If no node has the given
   280  * key, the last node on the search path is moved to the top of the
   281  * tree. This is the simplified top-down splaying algorithm from:
   282  * "Self-adjusting Binary Search Trees" by Sleator and Tarjan
   283  *
   284  * @param {number} key Key to splay the tree on.
   285  * @private
   286  */
   287 SplayTree.prototype.splay_ = function(key) {
   288   if (this.isEmpty()) {
   289     return;
   290   }
   291   // Create a dummy node.  The use of the dummy node is a bit
   292   // counter-intuitive: The right child of the dummy node will hold
   293   // the L tree of the algorithm.  The left child of the dummy node
   294   // will hold the R tree of the algorithm.  Using a dummy node, left
   295   // and right will always be nodes and we avoid special cases.
   296   var dummy, left, right;
   297   dummy = left = right = new SplayTree.Node(null, null);
   298   var current = this.root_;
   299   while (true) {
   300     if (key < current.key) {
   301       if (!current.left) {
   302         break;
   303       }
   304       if (key < current.left.key) {
   305         // Rotate right.
   306         var tmp = current.left;
   307         current.left = tmp.right;
   308         tmp.right = current;
   309         current = tmp;
   310         if (!current.left) {
   311           break;
   312         }
   313       }
   314       // Link right.
   315       right.left = current;
   316       right = current;
   317       current = current.left;
   318     } else if (key > current.key) {
   319       if (!current.right) {
   320         break;
   321       }
   322       if (key > current.right.key) {
   323         // Rotate left.
   324         var tmp = current.right;
   325         current.right = tmp.left;
   326         tmp.left = current;
   327         current = tmp;
   328         if (!current.right) {
   329           break;
   330         }
   331       }
   332       // Link left.
   333       left.right = current;
   334       left = current;
   335       current = current.right;
   336     } else {
   337       break;
   338     }
   339   }
   340   // Assemble.
   341   left.right = current.left;
   342   right.left = current.right;
   343   current.left = dummy.right;
   344   current.right = dummy.left;
   345   this.root_ = current;
   346 };
   349 /**
   350  * Constructs a Splay tree node.
   351  *
   352  * @param {number} key Key.
   353  * @param {*} value Value.
   354  */
   355 SplayTree.Node = function(key, value) {
   356   this.key = key;
   357   this.value = value;
   358 };
   361 /**
   362  * @type {SplayTree.Node}
   363  */
   364 SplayTree.Node.prototype.left = null;
   367 /**
   368  * @type {SplayTree.Node}
   369  */
   370 SplayTree.Node.prototype.right = null;
   373 /**
   374  * Performs an ordered traversal of the subtree starting at
   375  * this SplayTree.Node.
   376  *
   377  * @param {function(SplayTree.Node)} f Visitor function.
   378  * @private
   379  */
   380 SplayTree.Node.prototype.traverse_ = function(f) {
   381   var current = this;
   382   while (current) {
   383     var left = current.left;
   384     if (left) left.traverse_(f);
   385     f(current);
   386     current = current.right;
   387   }
   388 };
   390 SplaySetup();
   391 SplayRun();
   392 SplayTearDown();

mercurial