Home | History | Annotate | Download | only in cctest
      1 // Copyright 2011 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.
     27 
     28 // This is a supplementary file for test-log/EquivalenceOfLoggingAndTraversal.
     29 
     30 function parseState(s) {
     31   switch (s) {
     32   case "": return Profile.CodeState.COMPILED;
     33   case "~": return Profile.CodeState.OPTIMIZABLE;
     34   case "*": return Profile.CodeState.OPTIMIZED;
     35   }
     36   throw new Error("unknown code state: " + s);
     37 }
     38 
     39 function LogProcessor() {
     40   LogReader.call(this, {
     41       'code-creation': {
     42           parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'],
     43           processor: this.processCodeCreation },
     44       'code-move': { parsers: [parseInt, parseInt],
     45           processor: this.processCodeMove },
     46       'code-delete': null,
     47       'sfi-move': { parsers: [parseInt, parseInt],
     48           processor: this.processFunctionMove },
     49       'shared-library': null,
     50       'profiler': null,
     51       'tick': null });
     52   this.profile = new Profile();
     53 
     54 }
     55 LogProcessor.prototype.__proto__ = LogReader.prototype;
     56 
     57 LogProcessor.prototype.processCodeCreation = function(
     58     type, kind, start, size, name, maybe_func) {
     59   if (type != "LazyCompile" && type != "Script" && type != "Function") return;
     60   // Scripts will compile into anonymous functions starting at 1:1. Adjust the
     61   // name here so that it matches corrsponding function's name during the heap
     62   // traversal.
     63   if (type == "Script") name = " :1:1";
     64   // Discard types to avoid discrepancies in "LazyCompile" vs. "Function".
     65   type = "";
     66   if (maybe_func.length) {
     67     var funcAddr = parseInt(maybe_func[0]);
     68     var state = parseState(maybe_func[1]);
     69     this.profile.addFuncCode(type, name, start, size, funcAddr, state);
     70   } else {
     71     this.profile.addCode(type, name, start, size);
     72   }
     73 };
     74 
     75 LogProcessor.prototype.processCodeMove = function(from, to) {
     76   this.profile.moveCode(from, to);
     77 };
     78 
     79 LogProcessor.prototype.processFunctionMove = function(from, to) {
     80   this.profile.moveFunc(from, to);
     81 };
     82 
     83 function RunTest() {
     84   // _log must be provided externally.
     85   var log_lines = _log.split("\n");
     86   var line, pos = 0, log_lines_length = log_lines.length;
     87   if (log_lines_length < 2)
     88     return "log_lines_length < 2";
     89   var logging_processor = new LogProcessor();
     90   for ( ; pos < log_lines_length; ++pos) {
     91     line = log_lines[pos];
     92     if (line === "test-logging-done,\"\"") {
     93       ++pos;
     94       break;
     95     }
     96     logging_processor.processLogLine(line);
     97   }
     98   logging_processor.profile.cleanUpFuncEntries();
     99   var logging_entries =
    100     logging_processor.profile.codeMap_.getAllDynamicEntriesWithAddresses();
    101   if (logging_entries.length === 0)
    102     return "logging_entries.length === 0";
    103   var traversal_processor = new LogProcessor();
    104   for ( ; pos < log_lines_length; ++pos) {
    105     line = log_lines[pos];
    106     if (line === "test-traversal-done,\"\"") break;
    107     traversal_processor.processLogLine(line);
    108   }
    109   var traversal_entries =
    110     traversal_processor.profile.codeMap_.getAllDynamicEntriesWithAddresses();
    111   if (traversal_entries.length === 0)
    112     return "traversal_entries.length === 0";
    113 
    114   function addressComparator(entryA, entryB) {
    115     return entryA[0] < entryB[0] ? -1 : (entryA[0] > entryB[0] ? 1 : 0);
    116   }
    117 
    118   logging_entries.sort(addressComparator);
    119   traversal_entries.sort(addressComparator);
    120 
    121   function entityNamesEqual(entityA, entityB) {
    122     if ("getRawName" in entityB &&
    123         entityNamesEqual.builtins.indexOf(entityB.getRawName()) !== -1) {
    124       return true;
    125     }
    126     if (entityNamesEqual.builtins.indexOf(entityB.getName()) !== -1) return true;
    127     return entityA.getName() === entityB.getName();
    128   }
    129   entityNamesEqual.builtins =
    130     ["Boolean", "Function", "Number", "Object",
    131      "Script", "String", "RegExp", "Date", "Error"];
    132 
    133   function entitiesEqual(entityA, entityB) {
    134     if ((entityA === null && entityB !== null) ||
    135       (entityA !== null && entityB === null)) return true;
    136     return entityA.size === entityB.size && entityNamesEqual(entityA, entityB);
    137   }
    138 
    139   var l_pos = 0, t_pos = 0;
    140   var l_len = logging_entries.length, t_len = traversal_entries.length;
    141   var comparison = [];
    142   var equal = true;
    143   // Do a merge-like comparison of entries. At the same address we expect to
    144   // find the same entries. We skip builtins during log parsing, but compiled
    145   // functions traversal may erroneously recognize them as functions, so we are
    146   // expecting more functions in traversal vs. logging.
    147   // Since we don't track code deletions, logging can also report more entries
    148   // than traversal.
    149   while (l_pos < l_len && t_pos < t_len) {
    150     var entryA = logging_entries[l_pos];
    151     var entryB = traversal_entries[t_pos];
    152     var cmp = addressComparator(entryA, entryB);
    153     var entityA = entryA[1], entityB = entryB[1];
    154     var address = entryA[0];
    155     if (cmp < 0) {
    156       ++l_pos;
    157       entityB = null;
    158     } else if (cmp > 0) {
    159       ++t_pos;
    160       entityA = null;
    161       address = entryB[0];
    162     } else {
    163       ++l_pos;
    164       ++t_pos;
    165     }
    166     var entities_equal = entitiesEqual(entityA, entityB);
    167     if (!entities_equal) equal = false;
    168     comparison.push([entities_equal, address, entityA, entityB]);
    169   }
    170   return [equal, comparison];
    171 }
    172 
    173 var result = RunTest();
    174 if (typeof result !== "string") {
    175   var out = [];
    176   if (!result[0]) {
    177     var comparison = result[1];
    178     for (var i = 0, l = comparison.length; i < l; ++i) {
    179       var c = comparison[i];
    180       out.push((c[0] ? "  " : "* ") +
    181                c[1].toString(16) + " " +
    182                (c[2] ? c[2] : "---") + " " +
    183                (c[3] ? c[3] : "---"));
    184     }
    185   }
    186   result[0] ? true : out.join("\n");
    187 } else {
    188   result;
    189 }
    190