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, 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, start, size, name, maybe_func) {
     59   if (type != "LazyCompile" && type != "Script" && type != "Function") return;
     60   // Discard types to avoid discrepancies in "LazyCompile" vs. "Function".
     61   type = "";
     62   if (maybe_func.length) {
     63     var funcAddr = parseInt(maybe_func[0]);
     64     var state = parseState(maybe_func[1]);
     65     this.profile.addFuncCode(type, name, start, size, funcAddr, state);
     66   } else {
     67     this.profile.addCode(type, name, start, size);
     68   }
     69 };
     70 
     71 LogProcessor.prototype.processCodeMove = function(from, to) {
     72   this.profile.moveCode(from, to);
     73 };
     74 
     75 LogProcessor.prototype.processFunctionMove = function(from, to) {
     76   this.profile.moveFunc(from, to);
     77 };
     78 
     79 function RunTest() {
     80   // _log must be provided externally.
     81   var log_lines = _log.split("\n");
     82   var line, pos = 0, log_lines_length = log_lines.length;
     83   if (log_lines_length < 2)
     84     return "log_lines_length < 2";
     85   var logging_processor = new LogProcessor();
     86   for ( ; pos < log_lines_length; ++pos) {
     87     line = log_lines[pos];
     88     if (line === "test-logging-done,\"\"") {
     89       ++pos;
     90       break;
     91     }
     92     logging_processor.processLogLine(line);
     93   }
     94   logging_processor.profile.cleanUpFuncEntries();
     95   var logging_entries =
     96     logging_processor.profile.codeMap_.getAllDynamicEntriesWithAddresses();
     97   if (logging_entries.length === 0)
     98     return "logging_entries.length === 0";
     99   var traversal_processor = new LogProcessor();
    100   for ( ; pos < log_lines_length; ++pos) {
    101     line = log_lines[pos];
    102     if (line === "test-traversal-done,\"\"") break;
    103     traversal_processor.processLogLine(line);
    104   }
    105   var traversal_entries =
    106     traversal_processor.profile.codeMap_.getAllDynamicEntriesWithAddresses();
    107   if (traversal_entries.length === 0)
    108     return "traversal_entries.length === 0";
    109 
    110   function addressComparator(entryA, entryB) {
    111     return entryA[0] < entryB[0] ? -1 : (entryA[0] > entryB[0] ? 1 : 0);
    112   }
    113 
    114   logging_entries.sort(addressComparator);
    115   traversal_entries.sort(addressComparator);
    116 
    117   function entityNamesEqual(entityA, entityB) {
    118     if ("getRawName" in entityB &&
    119         entityNamesEqual.builtins.indexOf(entityB.getRawName()) !== -1) {
    120       return true;
    121     }
    122     if (entityNamesEqual.builtins.indexOf(entityB.getName()) !== -1) return true;
    123     return entityA.getName() === entityB.getName();
    124   }
    125   entityNamesEqual.builtins =
    126     ["Boolean", "Function", "Number", "Object",
    127      "Script", "String", "RegExp", "Date", "Error"];
    128 
    129   function entitiesEqual(entityA, entityB) {
    130     if ((entityA === null && entityB !== null) ||
    131       (entityA !== null && entityB === null)) return true;
    132     return entityA.size === entityB.size && entityNamesEqual(entityA, entityB);
    133   }
    134 
    135   var l_pos = 0, t_pos = 0;
    136   var l_len = logging_entries.length, t_len = traversal_entries.length;
    137   var comparison = [];
    138   var equal = true;
    139   // Do a merge-like comparison of entries. At the same address we expect to
    140   // find the same entries. We skip builtins during log parsing, but compiled
    141   // functions traversal may erroneously recognize them as functions, so we are
    142   // expecting more functions in traversal vs. logging.
    143   // Since we don't track code deletions, logging can also report more entries
    144   // than traversal.
    145   while (l_pos < l_len && t_pos < t_len) {
    146     var entryA = logging_entries[l_pos];
    147     var entryB = traversal_entries[t_pos];
    148     var cmp = addressComparator(entryA, entryB);
    149     var entityA = entryA[1], entityB = entryB[1];
    150     var address = entryA[0];
    151     if (cmp < 0) {
    152       ++l_pos;
    153       entityB = null;
    154     } else if (cmp > 0) {
    155       ++t_pos;
    156       entityA = null;
    157       address = entryB[0];
    158     } else {
    159       ++l_pos;
    160       ++t_pos;
    161     }
    162     var entities_equal = entitiesEqual(entityA, entityB);
    163     if (!entities_equal) equal = false;
    164     comparison.push([entities_equal, address, entityA, entityB]);
    165   }
    166   return [equal, comparison];
    167 }
    168 
    169 var result = RunTest();
    170 if (typeof result !== "string") {
    171   var out = [];
    172   if (!result[0]) {
    173     var comparison = result[1];
    174     for (var i = 0, l = comparison.length; i < l; ++i) {
    175       var c = comparison[i];
    176       out.push((c[0] ? "  " : "* ") +
    177                c[1].toString(16) + " " +
    178                (c[2] ? c[2] : "---") + " " +
    179                (c[3] ? c[3] : "---"));
    180     }
    181   }
    182   result[0] ? true : out.join("\n");
    183 } else {
    184   result;
    185 }
    186